import { sendUnaryData, ServerUnaryCall, status, UntypedHandleCall } from '@grpc/grpc-js';

import { GreeterServer, GreeterService, HelloRequest, HelloResponse, HelloMapRequest, HelloMapResponse, HelloErrRequest, HelloErrResponse } from '../models/helloworld';
import { logger, ServiceError } from '../utils';

/**
 * package helloworld
 * service Greeter
 */
class Greeter implements GreeterServer {
  [method: string]: UntypedHandleCall;

  /**
   * Implements the SayHello RPC method.
   */
  public sayHello(call: ServerUnaryCall<HelloRequest, HelloResponse>, callback: sendUnaryData<HelloResponse>): void {
    logger.info('sayHello', Date.now());

    const res: Partial<HelloResponse> = {};
    const { name } = call.request;
    logger.info('sayHelloName:', name);

    if (name === 'error') {
      // https://grpc.io/grpc/node/grpc.html#.status__anchor
      return callback(new ServiceError(status.INVALID_ARGUMENT, 'InvalidValue'), null);
    }

    const metadataValue = call.metadata.get('foo');
    logger.info('sayHelloMetadata:', metadataValue);

    res.message = metadataValue.length > 0
      ? `foo is ${metadataValue}`
      : `hello ${name}`;

    callback(null, HelloResponse.fromJSON(res));
  }

  public sayMap(call: ServerUnaryCall<HelloMapRequest, HelloMapResponse>, callback: sendUnaryData<HelloMapResponse>): void {
    logger.info('sayHello', Date.now());

    const res: Partial<HelloMapResponse> = {};
    const { name, age } = call.request;
    logger.info('sayHelloName:', name);

    if (name === 'error') {
      // https://grpc.io/grpc/node/grpc.html#.status__anchor
      return callback(new ServiceError(status.INVALID_ARGUMENT, 'InvalidValue'), null);
    }


    const metadataValue = call.metadata.get('foo');
    logger.info('sayHelloMetadata:', metadataValue);

    res.message = metadataValue.length > 0
      ? `foo is ${metadataValue}`
      : `hello ${name} you age is ${age}`;

    res.code = 200

    res.data = `responseData: ${name} ${age}`

    if (name === 'timeout') {
      setTimeout(() => {
        callback(null, HelloMapResponse.fromJSON(res));
      }, 1000 * 15)
    } else {
      callback(null, HelloMapResponse.fromJSON(res));
    }
  }

  public sayErr(call: ServerUnaryCall<HelloErrRequest, HelloErrResponse>, callback: sendUnaryData<HelloErrResponse>): void {
    logger.info('sayHello', Date.now());

    const { message } = call.request;
    logger.info('sayMessage:', message);

      // https://grpc.io/grpc/node/grpc.html#.status__anchor
    callback(new ServiceError(status.INVALID_ARGUMENT, 'this is a err'), null);
  }
}

export {
  Greeter,
  GreeterService,
};
